package fem2;

import java.util.ArrayList;

/**
 * abstract class to generate all the mesh used for model, include mesh reading
 * from outside (i.e gid) and mesh generated manually
 * 
 * @author hbui
 * 
 */
public abstract class MeshGenerator {

	/**
	 * 
	 * @param dim
	 *            space dimension
	 * @return list of nodes of the mesh
	 */
	public abstract ArrayList<double[]> getNodes(int dim);

	/**
	 * specify the connectivities for this mesh. Note that the index base for
	 * connectivity is 0.
	 * 
	 * @return the connectivities
	 */
	public abstract ArrayList<ArrayList<Integer>> getConnectivities();

	/**
	 * 
	 * @param dim
	 *            space dimension
	 * @return the mesh
	 */
	public Mesh getMesh(int dim) {
		Mesh mesh = new Mesh();
		/*
		 * add nodes
		 */
		ArrayList<double[]> nodes = getNodes(dim);
		int nn = nodes.size();
		Node[] N = new Node[nn];
		for (int i = 0; i < nn; i++) {
			double[] n = nodes.get(i);
			N[i] = mesh.addNode(new Node(n));
		}
		/*
		 * add faces/blocks
		 */
		ArrayList<ArrayList<Integer>> elements = getConnectivities();
		if (dim == 2) {
			int ne = elements.size();
			for (int i = 0; i < ne; i++) {
				ArrayList<Integer> enodesid = elements.get(i);
				Node[] enodes = new Node[enodesid.size()];
				for (int j = 0; j < enodes.length; j++) {
					enodes[j] = N[enodesid.get(j)];
				}
				if (enodes.length == 2) {
					Edge e = new Edge(enodes);
					mesh.addEdge(e);
				} else if (enodes.length > 2) {
					Face f = new Face(enodes);
					mesh.addFace(f);
				} else {
					Debugger.warn(this, "point element at node " + enodesid.get(0) + ", skipped");
				}
			}
		} else if (dim == 3) {
			int ne = elements.size();
			for (int i = 0; i < ne; i++) {
				ArrayList<Integer> enodesid = elements.get(i);
				Node[] enodes = new Node[enodesid.size()];
				for (int j = 0; j < enodes.length; j++) {
					enodes[j] = N[enodesid.get(j)];
				}
				if (enodes.length == 2) {
					Edge e = new Edge(enodes);
					mesh.addEdge(e);
				} else if (enodes.length == 3) {
					Face f = new Face(enodes);
					mesh.addFace(f);
				} else if (enodes.length > 3) {
					Block b = new Block(enodes);
					mesh.addBlock(b);
				} else {
					Debugger.warn(this, "point element at node " + enodesid.get(0) + ", skipped");
				}
			}
		} else {
			throw new Error("invalid dimension");
		}
		return mesh;
	}
}
